/* Autore: Nicola Agosti */
/*
Questo programma mostra:
 - come passare uno o più parametri, per riferimento, alle funzioni.
*/

#define _CRT_SECURE_NO_WARNINGS /* Necessario se utilizziamo Visual Studio */

#include <stdio.h>
#include <stdlib.h>

#define DIM 10 /* Costante utilizzata per dimensionare il vettore e la matrice */

/*
Prototipi delle funzioni
*/
void calcolaPerimetroAreaQuadrato(float, float*, float*); /* Procedura che calcola il perimetro e l'area di un quadrato dato il lato */

float mediaVettore(float[], int); /* Funzione che ritorna la media degli elementi del vettore passato come parametro */

void minMaxMatrice(int[][DIM], int, int, int*, int*); /* Funzione che calcola il minimo e il massimo degli elementi della matrice passata come parametro */

int main()
{
	float latoQuadrato = 7.3, perimQuadrato, areaQuadrato;
	float media, vettore[DIM];
	int matrice[DIM][DIM], min, max;
	int i, j;

	/* Inizializzo il vettore e la matrice */
	for (i = 0; i < DIM; i++)
	{
		vettore[i] = i * 2.3;
	}

	for (i = 0; i < DIM; i++)
	{
		for (j = 0; j < DIM; j++)
		{
			matrice[i][j] = i + j;
		}
	}

	/* Esempio 1: calcola il perimetro e l'area di un quadrato dato il lato */
	printf("ESEMPIO 1");
	printf("\nQuadrato di lato 7.3");
	calcolaPerimetroAreaQuadrato(latoQuadrato, &perimQuadrato, &areaQuadrato);
	printf("\nIl perimetro e\': %.2f\nL\'area e\': %.2f", perimQuadrato, areaQuadrato);

	/* Esempio 2: ritorna la media degli elementi del vettore passato come parametro */
	printf("\n\n\nESEMPIO 2");
	media = mediaVettore(vettore, DIM);
	printf("\nLa media e\' %.2f", media);

	/* Esempio 3: calcola il minimo e il massimo degli elementi della matrice passata come parametro */
	printf("\n\n\nESEMPIO 3");
	minMaxMatrice(matrice, DIM, DIM, &min, &max);
	printf("\nIl minimo e\' %d\nIl massimo e\': %d", min, max);

	printf("\n");

	return 0;
}

/* Procedura che calcola il perimetro e l'area di un quadrato dato il lato */
/*
Passare un parametro per riferimento significa che alla funzione non viene passata una copia della variabile,
ma un riferimento ad essa, e la conseguenza è che, a differenza del passaggio per valore, se modificassi il contenuto
della variabile (parametro), la modifica si "vedrebbe" anche al di fuori della funzione... viene modificato il contenuto
della variabile passata come parametro!

Per indicare che "voglio" che il parametro si una variabile passata per riferimento devo anteporre al nome della variabile il
carattere "*".
*/
void calcolaPerimetroAreaQuadrato(float lato, float *perimetro, float *area)
{
	/* Per "accedere" al contenuto di un parametro passato come riferimento devo anteporre al nome del parametro il carattere "*". */
	/*
	N.B. E' necessario prestare sempre molta attenzione alla priorità degli operatori, in caso di dubbi è sempre opportuno utilizzare 
	le parentesi tonde, ad esempio il metodo "sicuro" per "accedere" al contenuto del parametro "perimetro" passato per
	riferimento è scriverlo in questo modo "(*perimetro)".
	*/
	*perimetro = lato * 4;
	*area = lato * lato;
}

/* Funzione che ritorna la media degli elementi del vettore passato come parametro */
/*
I vettori (le stringhe) possono essere passati SOLO per riferimento e non possono essere ritornati dalle funzioni.

Per indicare che "voglio" passare un vettore come parametro (per riferimento) devo aggiungere al nome del parametro le parentesi quadre.
NON è necessario, ma non crea problemi, indicare la dimensione del vettore tra le parentesi quadre.
Ad esempio, nel nostro caso, posso "scrivere" il parametro in questi 3 modi:
- int vettore[]
- int vettore[DIM]
- int *vettore (quest'ultimo caso lo descriveremo più avanti quando parleremo dei puntatori)
*/
float mediaVettore(float vettore[], int dim)
{
	int i;
	float somma;

	/* Calcolo la somma degli elementi del vettore */
	for (i = 0, somma = 0; i < dim; i++)
	{
		somma += vettore[i];
	}

	/* Calcolo la media e ritorno il risultato */
	return somma / dim;
}

/* Funzione che calcola il minimo e il massimo degli elementi della matrice passata come parametro */
/*
Le matrici (i vettori di stringhe) possono essere passati SOLO per riferimento e non possono essere ritornati dalle funzioni.

Per indicare che "voglio" passare una matrice come parametro (per riferimento) devo aggiungere al nome del parametro la coppia
di parentesi quadre e, almeno nella seconda parentesi quadra indicare la reale dimensione della matrice (la lunghezza della riga).
NON è necessario, ma non crea problemi, indicare anche la prima dimensione della matrice.
Ad esempio, nel nostro caso, posso "scrivere" il parametro in questi 3 modi:
- int matrice[][DIM]
- int matrice[DIM][DIM]
*/
void minMaxMatrice(int matrice[][DIM], int nRighe, int nColonne, int *min, int *max)
{
	int i, j;

	/* Inizializzo il minimo e il massimo al primo valore della matrice */
	*min = matrice[0][0];
	*max = matrice[0][0];

	/* Scorro l'intera matrice e calcolo il massimo e il minimo */
	for (i = 0; i < DIM; i++)
	{
		for (j = 0; j < DIM; j++)
		{
			/* Massimo? */
			if (matrice[i][j] > *max)
			{
				*max = matrice[i][j];
			}

			/* Minimo? */
			if (matrice[i][j] < *min)
			{
				*min = matrice[i][j];
			}
		}
	}
}
